Initial implementation: Patchwave analysis CLI - #1
Merged
Conversation
Establish the build and contribution scaffolding ahead of the implementation: - package.json/bun.lock: runtime and dev dependencies - tsconfig.json: strict TS config with #src path alias - eslint.config.mjs, .prettierignore: lint/format config - bunfig.toml, vitest.config.ts, vitest.setup.ts: test runner config - .github workflows + bootstrap action: PR/main/test CI - .husky pre-commit/pre-push hooks - .claude/rules: team conventions (neverthrow, Context/fakes, bun-native APIs, testing patterns) - scripts/ensure-test-template.ts: test scaffolding helper
The injectable-dependency foundation everything else builds on, following the Context + XxxImpl/FakeXxx convention. - types.ts: shared domain types for collected data and the report - context.ts: Context interface + createContext() wiring - environment.ts, errors.ts, time.ts, concurrency.ts, logger.ts: cross-cutting primitives (env parsing, error helpers, Temporal wrappers, bounded concurrency, structured logging) - Clock, FileSystem, BaseIo/IoImpl: I/O dependency interfaces + production implementations - github/: GithubClient (REST/GraphQL), token resolution (auth.ts), and discriminated-union error mapping (errors.ts) - Analytics + anonymousId: opt-out PostHog telemetry with a stable anonymous id
Deterministic test doubles implementing the Context dependency
interfaces, swapped in without module mocking:
- testHelpers/Fake{Analytics,Clock,FileSystem,GithubClient,Io}.ts:
inspectable fakes for each injectable dependency
- testHelpers/MemoryStream.ts: in-memory writable for IO assertions
- testHelpers/createFakeContext.ts: assembles a fully-faked Context
- testFactories.ts: builders for domain fixtures used across tests
Per-domain GitHub collectors plus the classification heuristics they feed. Each collector accepts its client/IO via Context and returns a Result; per-repo failures are surfaced as warnings rather than aborting the run. Collectors: - repos: org repo listing + language breakdown - contributors: active committers - branchProtection: required-checks / protection rules - dependabotConfig: presence and shape of dependabot config - dependabotPrs: Dependabot PR history - cve: security/CVE alerts - reverts: revert detection, indexed against Dependabot PRs Heuristics: - bumpType: semver bump classification + dev-dependency detection
Turns collected data into the shippable report artifact. - aggregate.ts: folds collector output into the ReportBundle — per-repo and org-wide rollups, time series, risk/automation slices - costFormulas.ts: labor/cost model used by the savings estimates - bundle.ts: assembles report files and zips them (fflate) - html.ts: renders the single-file HTML report, inlining the built web bundle (dist/report-web) as a text import - testFactories.ts: report-layer fixture builders
The interactive single-page report embedded into the HTML artifact.
- web/App.tsx + acts/ (Verdict, CostStory, RiskStory, AutomatedStory,
CallToAction, MethodologyAppendix): the narrative report sections
- web/primitives/ (charts, citation, brand mark, rows): presentational
building blocks
- web/data/: reads the embedded ReportBundle + citations via context
- web/hooks/useAssumptions: user-tweakable cost assumptions
- web/format/: bytes/days/money formatters
- web/index*.{html,tsx}: production + dev (HMR) entrypoints, styles,
and fixtures
- scripts/build-report-web.ts: bundles the web app into dist/report-web
Wires the collectors and report pipeline behind a CLI and documents the project. - src/index.ts: bin entrypoint — resolves token, builds Context, sets up telemetry, delegates to main() - src/cli.ts: arg parsing, the collect -> aggregate -> render/bundle orchestration, and human-facing error formatting (the only place Results are unwrapped) - removes the placeholder root index.ts - README.md: usage and overview; CLAUDE.md: project conventions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Initial implementation of patchwave-analysis — a diagnostic CLI that measures Dependabot toil and CVE exposure across a GitHub org.
What it does
Crawls an org's repos and, per repo, collects language mix, Dependabot config, security (CVE) alerts, branch protection, active human contributors, and Dependabot PR history. It aggregates these into a cost model and renders a single self-contained HTML report plus a share-back zip of the raw data behind every metric.
Structure
src/collectors/) — one per data source, each returningResult/ResultAsync; partial per-repo failures are logged as warnings and don't kill the run.src/github/) — Octokit (REST + GraphQL) with retry/throttle, errors mapped to a flat discriminated union.src/report/) — aggregation, cost formulas, bundling, and HTML render that embeds the data into a React app.src/report/web/) — React UI bundled to one HTML file.src/) —Context-based dependency injection withXxxImpl/FakeXxxfor IO, clock, filesystem, analytics.Conventions
try/catchin business logic; the CLI entrypoint is the only place that unwraps).bun testfor unit (*.test.ts), vitest browser tests for React components (*.browser.test.tsx).Gates
lint,typecheck, andtest(76 bun + 6 vitest browser) all pass.Opening as a draft for review.